package com.csc.banking.service;

import java.util.HashMap;
import java.util.List;

import javax.persistence.NonUniqueResultException;
import javax.persistence.QueryTimeoutException;

import org.springframework.beans.factory.annotation.Autowired;

import com.csc.banking.dao.*;
import com.csc.banking.model.*;
import com.csc.banking.model.TransferAction;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

@Service
public class Services 
{
	
	@Autowired
	private BalanceDao balanceDao;
	@Autowired
	private CustomerDao customerDao;
	@Autowired
	private LockDao lockDao;
	@Autowired
	private PeriodTypeDao periodTypeDao;
	@Autowired
	private ProfileDao profileDao;
	@Autowired
	private TransactionDao transactionDao;
	@Autowired
	private TransactionActionDao transactionActionDao;
	@Autowired
	private TransactionTypeDao transactionTypeDao;
	@Autowired
	private TransferActionDao transferActionDao;
	
	private GenaricDao[] getDaoList()
	{
		GenaricDao[] res={balanceDao,customerDao,lockDao,periodTypeDao,profileDao,transactionDao,transactionActionDao,transactionTypeDao,transferActionDao};
		return res;
	}
	
	static HashMap<Class<?>,Integer> h=genH(); 
	
	private static HashMap<Class<?>,Integer> genH()
	{
		HashMap<Class<?>,Integer> h=new  HashMap<Class<?>,Integer>(); 
		h.put(Balance.class, 0);
		h.put(Customer.class, 1);	
		h.put(Lock.class, 2);
		h.put(PeriodType.class, 3);
		h.put(Profile.class, 4);
		h.put(Transaction.class, 5);
		h.put(TransactionAction.class, 6);
		h.put(TransactionType.class, 7);
		h.put(TransferAction.class, 8);
		return h;
	}
	
	GenaricDao getDao(EntityObject arg)
	{
		System.out.println(arg.getClass().getSimpleName()+"\n\n\n");
		return getDaoList()[h.get(arg.getClass())];
	}
	
	GenaricDao getDao(Class<?> arg)
	{
		return getDaoList()[h.get(arg)];
	}	
	
	@Transactional
	public EntityObject create(EntityObject arg)
	{
		GenaricDao dao=getDao(arg);
		if(dao.insert(arg)>0)
			return arg;
		return null;
	}
	
	@Transactional
	public EntityObject update(EntityObject arg)
	{
		GenaricDao dao=getDao(arg);
		if(dao.update(arg)>0)
				return arg;
			return null;
	}
	
	@Transactional
	public void delete(EntityObject arg)
	{
		GenaricDao dao=getDao(arg);
		dao.delete(arg);
	}	
	
	public Customer getCustomer(String userName,String password)
	{
		return customerDao.getCustomer(userName, password);
	}
	
	public Customer updateCustomer(Customer customer)
	{
		if(customerDao.update(customer)>0)
				return customer;
			return null;
	}
	
	
	
	@Transactional
	public List<Balance> getbalances(Customer customer)
	{
		return balanceDao.getBalances(customer);
	}
	
	public int firstValidate(Transaction currentTransaction,String from, String toAccountNumber, String amount)////remove
	{
		if(currentTransaction==null) return 200;//transaction terminated
		Customer thisCustomer = currentTransaction.getCustomer();
		Balance fromBalance = balanceDao.getBalance(from);
		if(fromBalance==null) return 1;//this account is not exist
		Balance toBalance = balanceDao.getBalance(toAccountNumber);
		if(toBalance==null) return 2;//destination is not exist
		double amount1=0;
		try
		{
			amount1=Double.valueOf(amount);
		}
		catch(Exception e)
		{
			return 3;//amount is not number
		}
		if(amount1<=0) return 4;//amont is negative
		
		if(thisCustomer.getCustomerId().equals(fromBalance.getCustomer().getCustomerId())==false)
			return 101;//there are something wrong with login action
		if(fromBalance.getBalance()<amount1) return 5;//account is not enaugh money to transfer
		return 0;
	}
	
	

	
	@Transactional
	public int transferFund(Transaction currentTransaction,Balance from, Balance toAccount, Double amount)
	{		
		Customer thisCustomer = currentTransaction.getCustomer();
		Customer toCustomer = toAccount.getCustomer();
		try
		{
			//if(toCustomer.getIsLock()==true) return 6;//destination is locked
			if(thisCustomer.getIsLock()==true) return 5;//account is locked
			
			
			
			TransactionAction transactionAction = new TransactionAction();
			transactionAction.setTransaction(currentTransaction);
			transactionAction.setTransactionTime(new Date());
			transactionAction.setTransactionType((TransactionType) transactionTypeDao.getTransactionType("Transfer Fund"));
			transactionActionDao.insert(transactionAction);
			
			TransferAction transferAction = new TransferAction(transactionAction,toCustomer);
			transferActionDao.insert(transferAction);
			
			from.setBalance(from.getBalance()-amount);
			toAccount.setBalance(toAccount.getBalance()+amount);
			
			balanceDao.update(from);
			balanceDao.update(toAccount);
			
			currentTransaction.setEndTime(new Date());
			transactionDao.update(currentTransaction);
			
			return 0;
		}
		catch(NonUniqueResultException e)
		{
			return 102;//account not exist
		}
		catch(QueryTimeoutException e)
		{
			return 201;// request timeout
		}
	}
	
	@Transactional
	public void endTransaction(Transaction transaction)
	{
		transaction.setEndTime(new Date());
		transactionDao.update(transaction);
	}
	
	public Balance getBalance(String accountNumber)
	{
		return balanceDao.getBalance(accountNumber);
	}
	public EntityObject getBalance(Long id)
	{
		 return balanceDao.getOne(id);
	}
	public EntityObject getCustomer(Long id)
	{
		 return customerDao.getOne(id);
	}
	public EntityObject getLock(Long id)
	{
		 return lockDao.getOne(id);
	}
	public EntityObject getPeriodType(Long id)
	{
		 return periodTypeDao.getOne(id);
	}
	public EntityObject getProfile(Long id)
	{
		 return profileDao.getOne(id);
	}
	public EntityObject getTransaction(Long id)
	{
		 return transactionDao.getOne(id);		 
	}
	public EntityObject getTransactionDetail(Long id)
	{
		 return transactionActionDao.getOne(id);		 
	}
	public EntityObject getTransactionType(Long id)
	{
		 return transactionTypeDao.getOne(id);		 
	}
	
	public List<EntityObject> getAll(Class<?> whichEntity)
	{
		GenaricDao dao=getDao(whichEntity);		 
		return dao.getAll();
	}
	
	public List<Transaction> getAllTransactionByCustomer(Customer customer)
	{
		return transactionDao.getAllTransactionsByCustomer(customer) ;
	}
	
	public Balance getDepositAccount(Customer customer)
	{
		return balanceDao.getDepositAccount(customer);
	}
}
